#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @Project:     rest_flask
# @File:        pattern_matcher.py
# @Author:      Fan GuiChuan
# @Date:        2025/6/26 15:34
# @Version:     Python3.7
# @Description:
import pyhyperscan


class PatternMatcher:
    def __del__(self):
        # 释放数据库
        if hasattr(self, 'db') and self.db:
            pyhyperscan.free_database(self.db)

    @staticmethod
    def safe_byte_offset_to_char_offset(s, byte_offset):
        encoded = s.encode('utf-8')
        while byte_offset > 0:
            try:
                return len(encoded[:byte_offset].decode('utf-8'))
            except UnicodeDecodeError:
                byte_offset -= 1  # 回退到上一个完整字符
        return 0

    def __init__(self, patterns, pattern_ids, logger):
        self.text = None
        self.patterns = []
        self.patterns_ids = []
        self.id_map = {}
        self.matches = []  # 存储匹配结果
        self.logger = logger

        # 检查模式有效性
        for index, pattern in enumerate(patterns):
            ret, msg = pyhyperscan.check_patterns(patterns, [pyhyperscan.HS_FLAG_DOTALL_PY] * len(patterns))
            if not ret:
                self.logger.error(f"Invalid patterns: {msg}")
            else:
                self.patterns.append(patterns[index])
                self.patterns_ids.append(pattern_ids[index])

        # 编译多模式数据库
        ids = list(range(len(patterns)))  # 为每个模式分配唯一ID
        flags = [pyhyperscan.HS_FLAG_DOTALL_PY | pyhyperscan.HS_FLAG_SINGLEMATCH_PY] * len(self.patterns)
        self.db = pyhyperscan.compile_multi_patterns(self.patterns, flags, ids)

    def on_match(self, id, from_, to, flags):
        """匹配回调函数，存储结果到列表（同一个ID只返回一次）"""
        from_ = self.safe_byte_offset_to_char_offset(self.text, from_)
        to = self.safe_byte_offset_to_char_offset(self.text, to)

        # 检查是否已经存储过该 ID 的匹配结果
        if any(match['feature_id'] == self.patterns_ids[id]['label_id'] for match in self.matches):
            return
        label_id = self.patterns_ids[id].get('label_id')
        self.matches.append({
            'feature_id': label_id,
            'feature_name': self.patterns_ids[id].get('label_name'),
            'feature_code': f"L{label_id}",
            'level_code': self.patterns_ids[id].get('level_code'),
            'level_id': self.patterns_ids[id].get('level_id'),
            'rule_id': self.patterns_ids[id].get('rule_id'),
            'template_id': self.patterns_ids[id].get('template_id'),
            'from': from_,
            'to': to,
            'match': self.text[from_:to],  # 提取匹配文本
            'identify_type': 0,
            'identify_type_name': 'regex'
        })

    def match_all(self, scan_text: str):
        """扫描文本并返回所有匹配结果"""
        self.matches = []  # 清空旧结果
        self.text = scan_text    # 存储文本供回调函数使用
        pyhyperscan.scan_data(self.db, self.text, self.on_match)
        return self.matches


if __name__ == '__main__':
    # 示例用法
    patterns = ['123', '男|女']  # Hyperscan需要字节模式（bytes）
    pattern_ids = [
        {'label_id': 1, 'label_name': '数字123', 'level_code': 'L1', 'rule_id': 'R1'},
        {'label_id': 2, 'label_name': '性别', 'level_code': 'L2', 'rule_id': 'R2'}
    ]
    matcher = PatternMatcher(patterns, pattern_ids)

    text = 'hello wo男rld123女男'
    print(f"len text: {len(text)}")
    results = matcher.match_all(text)
    print(f"results: {results}")
    # 打印匹配结果
    for match in results:
        print(f"匹配到模式 ID={match['feature_id']} 名称={match['feature_name']}")
